package com.lj.tools.net;


import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import lombok.Data;
import org.apache.hc.client5.http.classic.ExecChainHandler;
import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.classic.methods.HttpPost;
import org.apache.hc.client5.http.cookie.BasicCookieStore;
import org.apache.hc.client5.http.cookie.CookieStore;
import org.apache.hc.client5.http.entity.UrlEncodedFormEntity;
import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder;
import org.apache.hc.client5.http.impl.ChainElement;
import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
import org.apache.hc.client5.http.impl.async.HttpAsyncClients;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.protocol.HttpClientContext;
import org.apache.hc.core5.http.*;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.http.io.entity.StringEntity;
import org.apache.hc.core5.http.message.BasicHeader;
import org.apache.hc.core5.http.message.BasicNameValuePair;
import org.apache.hc.core5.net.URIBuilder;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;


@Data
public class NetClient {

    private List<NameValuePair> nameValuePairs = new ArrayList<>();
    private HttpClientContext httpClientContext;
    private CookieStore cookieStore;
    private List<Header> headers = new ArrayList<>();

    private CloseableHttpClient closeableHttpClient;
    private CloseableHttpAsyncClient closeableHttpAsyncClient;
    private HttpRequestInterceptor httpRequestInterceptor;
    private ExecChainHandler execChainHandler;

    /**
     * 生成客户端
     * */
    public static NetClient newInstance(){
        NetClient netClient = new NetClient();
        return netClient;
    }

    private NetClient(){
        //HTTP 请求上下文
        httpClientContext = HttpClientContext.create();
        cookieStore = new BasicCookieStore();
        httpClientContext.setCookieStore(cookieStore);

        closeableHttpClient = HttpClients.createDefault();
        closeableHttpAsyncClient = HttpAsyncClients.createDefault();
    }

    /**
     * 自定义数据
     * @param httpRequestInterceptor 请求数据
     * @param execChainHandler 数据链表
     * */
    public void initCustom(HttpRequestInterceptor httpRequestInterceptor, ExecChainHandler execChainHandler){
        closeableHttpClient = HttpClients.custom()
                .addRequestInterceptorFirst(httpRequestInterceptor)
                .addExecInterceptorAfter(ChainElement.PROTOCOL.name(), "custom", execChainHandler)
                .build();
    }


    /**
     * 设置请求参数
     * */
    public void addParam(String name, String value){
        nameValuePairs.add(new BasicNameValuePair(name, value));
    }

    public void clearParam(){
        nameValuePairs.clear();
    }

    public void setHeader(String name, String value){
        for (Header header:headers){
            if (name.equals(header.getName())){
                headers.remove(header);
                break;
            }
        }
        headers.add(new BasicHeader(name, value));
    }


    public static <T> T parse(CloseableHttpResponse response, Class<T> cls) throws IOException, ParseException {
        return JSON.parseObject(EntityUtils.toString(response.getEntity()), cls);
    }

    public static String parseString(CloseableHttpResponse response) throws IOException, ParseException {
        return EntityUtils.toString(response.getEntity());
    }

    public static byte[] parseBytes(CloseableHttpResponse response) throws IOException {
        return EntityUtils.toByteArray(response.getEntity());
    }



    public CloseableHttpResponse get(String url){
        try{
            HttpGet httpGet = new HttpGet(url);
            if (nameValuePairs.size() > 0){
                URI uri = new URIBuilder(new URI(url))
                        .addParameters(nameValuePairs)
                        .build();
                httpGet.setUri(uri);
            }
            headers.forEach( header -> {
                httpGet.setHeader(header.getName(), header.getValue());
            });
            CloseableHttpResponse response = closeableHttpClient.execute(httpGet, httpClientContext);
            return response;
        } catch (IOException | URISyntaxException e) {
            e.printStackTrace();
            return null;
        }
    }

    public CloseableHttpResponse postForm(String url) throws IOException {
        HttpPost httpPost = new HttpPost(url);
        if (nameValuePairs.size() > 0){
            httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
        }
        headers.forEach( header -> {
            httpPost.setHeader(header.getName(), header.getValue());
        });
        CloseableHttpResponse response = closeableHttpClient.execute(httpPost, httpClientContext);
        return response;
    }

    public CloseableHttpResponse postJson(String url) throws IOException {
        JSONObject json = new JSONObject();
        if (nameValuePairs.size() > 0 ){
            nameValuePairs.forEach( nameValuePair -> {
                json.put(nameValuePair.getName(), nameValuePair.getValue());
            });
        }
        return postJson(url, json.toJSONString());
    }

    public CloseableHttpResponse postJson(String url, JSONObject json) throws IOException {
        return postJson(url, json.toJSONString());
    }

    public CloseableHttpResponse postJson(String url, String jsonBody) throws IOException {
        HttpPost httpPost = new HttpPost(url);
        headers.forEach( header -> {
            httpPost.setHeader(header.getName(), header.getValue());
        });
        httpPost.setEntity(new StringEntity(jsonBody, ContentType.APPLICATION_JSON));
        CloseableHttpResponse response = closeableHttpClient.execute(httpPost, httpClientContext);
        return response;
    }

    /**
     * 文件--
     * */


    public CloseableHttpResponse postFile(String url, File file) throws IOException {
        return postFile(url, new FileInputStream(file));
    }

    public CloseableHttpResponse postFile(String url, InputStream file) throws IOException {
        HttpPost httpPost = new HttpPost(url);
        httpPost.addHeader("Content-type", "application/json;charset=UTF-8");

        MultipartEntityBuilder builder = MultipartEntityBuilder.create();
        builder.addBinaryBody("file", file);
        if(nameValuePairs.size() >  0){
            nameValuePairs.forEach( nameValuePair -> {
                builder.addTextBody(nameValuePair.getName(), nameValuePair.getValue());
            });
        }
        httpPost.setEntity(builder.build());
        headers.forEach( header -> {
            httpPost.setHeader(header.getName(), header.getValue());
        });
        CloseableHttpResponse response = closeableHttpClient.execute(httpPost);
        return response;
    }

}
